import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import $ from 'jquery';

/**
 *  提示主键
 */
export default class Tooltip extends Component{

	static propsTypes = {
		title: PropTypes.string.isRequired,
		align: PropTypes.oneOf(['top', 'left', 'bottom', 'right']),
		target: PropTypes.element //触发元素
	}

	static defaultProps = {
		align: 'top'
	}

	constructor(props){
		super(props);
		this.eFlag = false;
		this.div = null;
	}

	hover(){
		if(this.eFlag) return;
		let $target = this.target,
			self = this;
		this.eFlag = true;
		$target.on('mouseenter.tooltip', function(){
			let {title} = self.state;
			if(title){
				self.div = document.createElement('div');
				document.body.appendChild(self.div);
				ReactDOM.render(self.renderTip(), self.div, function(){
					self.setAlign(this);
				});
			}
		}).on('mouseleave.tooltip', function(){
			self.removeTip();
		});
	}
	
	setAlign(that){
		let {align} = this.props
			, $tip = $(that)
		    , offset = $tip.offset()
		    , toff = this.target.offset()
		    , th = this.target.outerHeight()
		    , tw = this.target.outerWidth()
		    , docTop = $(document).scrollTop()
		    , docLeft = $(document).scrollLeft()
		    , top = toff.top - docTop
		    , left = toff.left - docLeft
		    , tipH = $tip.height()
		    , tipW = $tip.outerWidth()
		    , w = $(window).width()
		    , h = $(window).height()
		    , dis = 0;
		switch(align){
			case 'top':
				if(top < tipH && left >= 0){
					align = 'bottom';
				}else if(left < 0){
					align = 'right';
				}else if(left + tw + tipW + dis > w){ //右边超出窗口边界
					align = 'left';
				}
				break;
			case 'bottom':
				if(top + th + tipH + dis > h && left > 0){  //超出下边界
					align = 'top';
				}else if(left < 0){
					align = 'right';
				}else if(left + tw + tipW + dis > w){ //右边超出窗口边界
					align = 'left';
				}
				break;
			case 'left':
				if(left - tipW - dis < 0){
					align = 'right';
				}
				break;
			case 'right':
				if(left + tw + tipW + dis > w){
					align = 'left';
				}
				break;
		}
		$tip.addClass('rd-align-' + align);
		tipW = $tip.outerWidth();
		tipH = $tip.outerHeight();
		switch(align){
			case 'top':
				top = toff.top - tipH - dis;
				left = toff.left + (tw - tipW) / 2;
			break;
			case 'bottom':
				top = toff.top + th + dis;
				left = toff.left + (tw - tipW) / 2;
			break;
			case 'left':
				top = toff.top + (th - tipH) / 2;
				left = toff.left - tipW - dis;
			break;
			case 'right':
				top = toff.top + (th - tipH) / 2;
				left = toff.left + tw + dis;
			break;
		}
		$tip.offset({top: top, left: left});
	}

	removeTip(){
		if(this.div != null){
			ReactDOM.unmountComponentAtNode(this.div);
			document.body.removeChild(this.div);
			this.div = null;
		}
	}

	componentWillUnmount(){
		this.target.off('.tooltip');
	}
	
	componentDidMount(){
		if(this.props.target){
			this.target = $(ReactDOM.findDOMNode(this.props.target));
		}else{
			this.target = $(ReactDOM.findDOMNode(this));
		}
		let title = this.props.title;
		this.setState({title}, function(){
			if(title){
				this.hover();
			}
		});
	}

	componentWillReceiveProps(nextProps){
		if(!nextProps.title){
			this.removeTip();
			this.setState({title: undefined});
		}else{
			this.setState({title: nextProps.title}, function(){
				this.hover();
			});
		}
	}

	renderTip(){
		let {title} = this.state,
			cls = classNames({
				'rd-tooltip': true
			});

		return (
			<div className={cls}>
				<div className='rd-tooltip-arrow'>
				</div>
				<div className='rd-tooltip-title'>
					{title}
				</div>
			</div>
		)
	}

	render(){
		if(this.props.target){
			return null;
		}else{
			return React.Children.only(this.props.children);
		}
	}
}